/*
 * サンプル (elf.c)
 * enemy-unit 2 Made by M.
 * パラメータのみで勝っているという感じ。
 * 中身をみればおのずと弱点が見えてくる。（見るまでもないけど）
 */
#include <system.h>
#include <v93.h>
#include <common.h>
#include "spec.h"
#include "vardecl.h"
#include "service.h"

#define ELF_MIN_SPEED   0.043   /* これ以下のスピードならアクセル */
#define ELF_LIMIT_SPEED 0.045   /* これ以上のスピードならブレーキ */
#define ELF_LIMIT_DIST  1.300   /* 端がこれ以下に近付いたら逃げる */
#define ELF_DOWN_SPEED  0.005   /* 曲がるときにこれ以上なら減速する */
#define ELF_ENEMY_DIST  0.010   /* これ以下に敵に近付いたら曲がる */
#define ELF_ATTACK_SPEED 0.080  /* この速度までならアタックする */

typedef enum {          /* 方向をenumで宣言しておく */
  D_FRONT,
  D_BACK,
  D_LEFT,
  D_RIGHT,
  D_NULL
}DIR;

DIR ElfBrain(int);    /* あたまの宣言 */

/*
--------------------------------------------------------------
 * メインルーチン
 * 注意点：ループは作らない。
 *         一連の動作で、S_TurnLeft,S_TurnRightは１度だけ呼ぶ
--------------------------------------------------------------
 */
void
ElfMain(int which)
{
  int         iLRflag;
  int         iFBflag;
  QuadDist    *qDistance;
  direct_t    EnemyDir;

  iFBflag = D_NULL;
  iLRflag = D_NULL;
  qDistance = S_CheckDist(which);

  /* 早すぎたらスピードを落とす */
  if (S_GetSpeed(which) >= ELF_LIMIT_SPEED){
    iFBflag = D_BACK;
  }
  /* 端が近かったら逃げる */
  if(qDistance->dFrontDist < ELF_LIMIT_DIST){
    if (S_GetSpeed(which) >= ELF_DOWN_SPEED){
      iFBflag = D_BACK;
    }
    /* どっちに曲がったら良いのか無い頭をつかって考える */
    EnemyDir = S_SearchEnemy(which);
    /* 敵が後ろにいるなら、落ちない方向へ曲がる */
    if(EnemyDir < 0){
      iLRflag = ElfBrain(which);
    } else {
      if(EnemyDir < 900) {
        iLRflag = D_LEFT;
      }
      if(EnemyDir > 2700) {
        iLRflag = D_RIGHT;
      }
    }
  } else {
/*----------------------------
端が近くなかったら、敵を探す
----------------------------*/
    EnemyDir = S_SearchEnemy(which);
    if(EnemyDir < 0) {
      /* 後ろにいるなら、右に曲がる */
      iLRflag = D_RIGHT;
    }
    else{
      if(EnemyDir < 900) {
        /* 左にいるなら、左に曲がる */
        iLRflag = D_LEFT;
      }
      if(EnemyDir > 2700) {
        /* 右にいるなら、右に曲がる */
        iLRflag = D_RIGHT;
      }
      if(EnemyDir <= 200 || EnemyDir >= 3400) {
        /* 正面にいるなら、加速する */
        /* この時一定より近い距離なら変化をあたえて当たりに行く */
        if(S_CalcEnemyDist(which) < ELF_ENEMY_DIST){
          iLRflag = ElfBrain(which);
          if(S_GetSpeed(which) >= ELF_ATTACK_SPEED){
            iFBflag = D_NULL;
          } else {
            iFBflag = D_FRONT;
          }
        } else {
          iLRflag = D_NULL;
          iFBflag = D_FRONT;
        }
      }
    }
/*
--------------------------
遅かったらスピードをあげる
--------------------------
 */
    if (S_GetSpeed(which) <= ELF_MIN_SPEED) {
      iFBflag = D_FRONT;
    }
  }
  /* 左側に端が接近していたら、右に曲がる */
  if(qDistance->dLeftDist < ELF_LIMIT_DIST){ iLRflag = D_RIGHT; }

  /* 右側に端が接近していたら、左に曲がる */
  if(qDistance->dRightDist < ELF_LIMIT_DIST){ iLRflag = D_LEFT; }

  /* 後ろが近かったらスピードをあげる と同時に端から逃げる */
  if (qDistance->dBackDist < ELF_LIMIT_DIST){
    iFBflag = D_FRONT; 
    iLRflag = ElfBrain(which);
  }

/*
----------------------------------------------------
決定された行動パターンから、実際に行動にうつす。
----------------------------------------------------
 */
  switch(iLRflag){
    case D_LEFT:
      S_TurnLeft(which);
      break;
    case D_RIGHT:
      S_TurnRight(which);
      break;
    default:
      break;
  }
  switch(iFBflag){
    case D_FRONT:
      S_Forward(which);
      break;
    case D_BACK:
      S_Backward(which);
      break;
    default:
      break;
  }
}

/*
--------------------------------------------------------------
 * あたま
 *（どっちに曲がるか考える)
 * ただし、壁が近い場合のみ。
 * dwarfに使っている判定ルーチンと同じである。
--------------------------------------------------------------
 */
DIR
ElfBrain(int which)
{
  float     fMyX,fMyY;
  direct_t  dtMyDir;
  DIR       DWhich;

  /* 自分の情報を拾う */
  /* 角度は0.1°単位なので、10で割る */
  /* 内部でのＸＹ座標と角度は、Ｘ＝０の線を０°として
     扱っているので変換を行う */
  fMyX = -1 * S_CheckY(which);
  fMyY = S_CheckX(which);
  dtMyDir = S_CheckDir(which) / 10;

  /* フィールドを４５°単位で８分割し、
     場所と向きによって曲がる方向を決める */
  if( fMyX > 0 && fMyY > 0 ){
    if( fMyX > fMyY ){
/* 1 */
      if(dtMyDir > 0 && dtMyDir < 180)
        DWhich = D_LEFT;
      else
        DWhich = D_RIGHT;
    }
    else{
/* 2 */
      if(dtMyDir < 90 || dtMyDir > 270 )
        DWhich = D_RIGHT;
      else
        DWhich = D_LEFT;
    }
  }
  else
  if( fMyX < 0 && fMyY > 0 ){
    if( abs(fMyX) > abs(fMyY) ){
/* 4 */
      if(dtMyDir > 0 && dtMyDir < 180)
        DWhich = D_RIGHT;
      else
        DWhich = D_LEFT;
    } else {
/* 3 */
      if(dtMyDir < 90 || dtMyDir > 270 )
        DWhich = D_RIGHT;
      else
        DWhich = D_LEFT;
    }
  } else
  if( fMyX < 0 && fMyY < 0 ){
    if( fMyX > fMyY ){
/* 6 */
      if(dtMyDir < 90 || dtMyDir > 270)
        DWhich = D_LEFT;
      else
        DWhich = D_RIGHT;
    } else {
/* 5 */
      if(dtMyDir > 0 && dtMyDir < 180)
        DWhich = D_RIGHT;
      else
        DWhich = D_LEFT;
    }
  } else {
    if( fMyX > 0 && fMyY < 0 ){
      if( abs(fMyX) < abs(fMyY) ){
/* 7 */
        if(dtMyDir > 0 && dtMyDir < 180)
          DWhich = D_RIGHT;
        else
          DWhich = D_LEFT;
      } else {
/* 8 */
        if(dtMyDir < 90 || dtMyDir > 270)
          DWhich = D_LEFT;
       else
          DWhich = D_RIGHT;
        }
      } else {
      DWhich = D_RIGHT;
    }
  }
  return DWhich;
}

